"""
任务调度服务
负责定时任务的调度和管理
"""

import logging
import threading
import time
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional, Callable
from dataclasses import dataclass
from enum import Enum

try:
    from apscheduler.schedulers.background import BackgroundScheduler
    from apscheduler.triggers.interval import IntervalTrigger
    from apscheduler.triggers.cron import CronTrigger
    from apscheduler.triggers.date import DateTrigger
    APSCHEDULER_AVAILABLE = True
except ImportError:
    APSCHEDULER_AVAILABLE = False

class TaskType(Enum):
    """任务类型"""
    INTERVAL = "interval"  # 间隔任务
    CRON = "cron"         # 定时任务
    ONCE = "once"         # 一次性任务

class TaskStatus(Enum):
    """任务状态"""
    PENDING = "pending"
    RUNNING = "running"
    PAUSED = "paused"
    COMPLETED = "completed"
    FAILED = "failed"

@dataclass
class ScheduledTask:
    """调度任务"""
    id: str
    name: str
    task_type: TaskType
    func: Callable
    args: tuple = ()
    kwargs: dict = None
    
    # 间隔任务参数
    interval_seconds: Optional[int] = None
    
    # 定时任务参数
    cron_expression: Optional[str] = None
    
    # 一次性任务参数
    run_date: Optional[datetime] = None
    
    # 任务状态
    status: TaskStatus = TaskStatus.PENDING
    enabled: bool = True
    
    # 执行统计
    run_count: int = 0
    last_run_time: Optional[datetime] = None
    last_success_time: Optional[datetime] = None
    error_count: int = 0
    last_error: Optional[str] = None
    
    def __post_init__(self):
        if self.kwargs is None:
            self.kwargs = {}

class SchedulerService:
    """任务调度服务"""
    
    def __init__(self):
        self.logger = logging.getLogger(self.__class__.__name__)
        
        if not APSCHEDULER_AVAILABLE:
            self.logger.warning("APScheduler未安装，使用简单调度器")
            self.scheduler = None
            self.use_simple_scheduler = True
        else:
            self.scheduler = BackgroundScheduler()
            self.use_simple_scheduler = False
        
        # 任务管理
        self.tasks: Dict[str, ScheduledTask] = {}
        
        # 简单调度器相关
        self.simple_scheduler_thread = None
        self.simple_scheduler_running = False
        
        # 线程锁
        self.lock = threading.RLock()
        
        self.logger.info("任务调度服务初始化完成")
    
    def start(self):
        """启动调度服务"""
        if self.use_simple_scheduler:
            self._start_simple_scheduler()
        else:
            self.scheduler.start()
        
        self.logger.info("任务调度服务已启动")
    
    def stop(self):
        """停止调度服务"""
        if self.use_simple_scheduler:
            self._stop_simple_scheduler()
        else:
            if self.scheduler.running:
                self.scheduler.shutdown()
        
        self.logger.info("任务调度服务已停止")
    
    def add_interval_task(self, task_id: str, name: str, func: Callable, 
                         interval_seconds: int, args: tuple = (), kwargs: dict = None) -> bool:
        """添加间隔任务"""
        try:
            task = ScheduledTask(
                id=task_id,
                name=name,
                task_type=TaskType.INTERVAL,
                func=func,
                args=args,
                kwargs=kwargs or {},
                interval_seconds=interval_seconds
            )
            
            with self.lock:
                self.tasks[task_id] = task
            
            if not self.use_simple_scheduler:
                self.scheduler.add_job(
                    func=self._execute_task,
                    args=(task_id,),
                    trigger=IntervalTrigger(seconds=interval_seconds),
                    id=task_id,
                    name=name,
                    replace_existing=True
                )
            
            self.logger.info(f"添加间隔任务: {name} (每{interval_seconds}秒)")
            return True
            
        except Exception as e:
            self.logger.error(f"添加间隔任务失败: {e}")
            return False
    
    def add_cron_task(self, task_id: str, name: str, func: Callable,
                     cron_expression: str, args: tuple = (), kwargs: dict = None) -> bool:
        """添加定时任务"""
        try:
            task = ScheduledTask(
                id=task_id,
                name=name,
                task_type=TaskType.CRON,
                func=func,
                args=args,
                kwargs=kwargs or {},
                cron_expression=cron_expression
            )
            
            with self.lock:
                self.tasks[task_id] = task
            
            if not self.use_simple_scheduler:
                # 解析cron表达式
                cron_parts = cron_expression.split()
                if len(cron_parts) >= 5:
                    minute, hour, day, month, day_of_week = cron_parts[:5]
                    
                    self.scheduler.add_job(
                        func=self._execute_task,
                        args=(task_id,),
                        trigger=CronTrigger(
                            minute=minute,
                            hour=hour,
                            day=day,
                            month=month,
                            day_of_week=day_of_week
                        ),
                        id=task_id,
                        name=name,
                        replace_existing=True
                    )
            
            self.logger.info(f"添加定时任务: {name} ({cron_expression})")
            return True
            
        except Exception as e:
            self.logger.error(f"添加定时任务失败: {e}")
            return False
    
    def add_once_task(self, task_id: str, name: str, func: Callable,
                     run_date: datetime, args: tuple = (), kwargs: dict = None) -> bool:
        """添加一次性任务"""
        try:
            task = ScheduledTask(
                id=task_id,
                name=name,
                task_type=TaskType.ONCE,
                func=func,
                args=args,
                kwargs=kwargs or {},
                run_date=run_date
            )
            
            with self.lock:
                self.tasks[task_id] = task
            
            if not self.use_simple_scheduler:
                self.scheduler.add_job(
                    func=self._execute_task,
                    args=(task_id,),
                    trigger=DateTrigger(run_date=run_date),
                    id=task_id,
                    name=name,
                    replace_existing=True
                )
            
            self.logger.info(f"添加一次性任务: {name} ({run_date})")
            return True
            
        except Exception as e:
            self.logger.error(f"添加一次性任务失败: {e}")
            return False
    
    def remove_task(self, task_id: str) -> bool:
        """移除任务"""
        try:
            with self.lock:
                if task_id in self.tasks:
                    del self.tasks[task_id]
            
            if not self.use_simple_scheduler:
                self.scheduler.remove_job(task_id)
            
            self.logger.info(f"移除任务: {task_id}")
            return True
            
        except Exception as e:
            self.logger.error(f"移除任务失败: {e}")
            return False
    
    def pause_task(self, task_id: str) -> bool:
        """暂停任务"""
        try:
            with self.lock:
                if task_id in self.tasks:
                    self.tasks[task_id].status = TaskStatus.PAUSED
                    self.tasks[task_id].enabled = False
            
            if not self.use_simple_scheduler:
                self.scheduler.pause_job(task_id)
            
            self.logger.info(f"暂停任务: {task_id}")
            return True
            
        except Exception as e:
            self.logger.error(f"暂停任务失败: {e}")
            return False
    
    def resume_task(self, task_id: str) -> bool:
        """恢复任务"""
        try:
            with self.lock:
                if task_id in self.tasks:
                    self.tasks[task_id].status = TaskStatus.PENDING
                    self.tasks[task_id].enabled = True
            
            if not self.use_simple_scheduler:
                self.scheduler.resume_job(task_id)
            
            self.logger.info(f"恢复任务: {task_id}")
            return True
            
        except Exception as e:
            self.logger.error(f"恢复任务失败: {e}")
            return False
    
    def get_task_info(self, task_id: str) -> Optional[Dict[str, Any]]:
        """获取任务信息"""
        with self.lock:
            if task_id not in self.tasks:
                return None
            
            task = self.tasks[task_id]
            return {
                'id': task.id,
                'name': task.name,
                'type': task.task_type.value,
                'status': task.status.value,
                'enabled': task.enabled,
                'run_count': task.run_count,
                'last_run_time': task.last_run_time.isoformat() if task.last_run_time else None,
                'last_success_time': task.last_success_time.isoformat() if task.last_success_time else None,
                'error_count': task.error_count,
                'last_error': task.last_error,
                'interval_seconds': task.interval_seconds,
                'cron_expression': task.cron_expression,
                'run_date': task.run_date.isoformat() if task.run_date else None
            }
    
    def get_all_tasks(self) -> List[Dict[str, Any]]:
        """获取所有任务信息"""
        with self.lock:
            return [self.get_task_info(task_id) for task_id in self.tasks.keys()]
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取调度统计信息"""
        with self.lock:
            total_tasks = len(self.tasks)
            running_tasks = sum(1 for task in self.tasks.values() if task.status == TaskStatus.RUNNING)
            paused_tasks = sum(1 for task in self.tasks.values() if task.status == TaskStatus.PAUSED)
            failed_tasks = sum(1 for task in self.tasks.values() if task.error_count > 0)
            
            return {
                'total_tasks': total_tasks,
                'running_tasks': running_tasks,
                'paused_tasks': paused_tasks,
                'failed_tasks': failed_tasks,
                'scheduler_type': 'simple' if self.use_simple_scheduler else 'apscheduler'
            }
    
    def _execute_task(self, task_id: str):
        """执行任务"""
        with self.lock:
            if task_id not in self.tasks:
                return
            
            task = self.tasks[task_id]
            
            if not task.enabled:
                return
            
            task.status = TaskStatus.RUNNING
            task.run_count += 1
            task.last_run_time = datetime.now()
        
        try:
            self.logger.debug(f"执行任务: {task.name}")
            
            # 执行任务函数
            result = task.func(*task.args, **task.kwargs)
            
            with self.lock:
                task.status = TaskStatus.COMPLETED if task.task_type == TaskType.ONCE else TaskStatus.PENDING
                task.last_success_time = datetime.now()
                task.last_error = None
            
            self.logger.debug(f"任务执行成功: {task.name}")
            
        except Exception as e:
            error_msg = str(e)
            
            with self.lock:
                task.status = TaskStatus.FAILED
                task.error_count += 1
                task.last_error = error_msg
            
            self.logger.error(f"任务执行失败 {task.name}: {error_msg}")
    
    def _start_simple_scheduler(self):
        """启动简单调度器"""
        self.simple_scheduler_running = True
        self.simple_scheduler_thread = threading.Thread(
            target=self._simple_scheduler_worker,
            name="SimpleSchedulerWorker"
        )
        self.simple_scheduler_thread.daemon = True
        self.simple_scheduler_thread.start()
    
    def _stop_simple_scheduler(self):
        """停止简单调度器"""
        self.simple_scheduler_running = False
        if self.simple_scheduler_thread:
            self.simple_scheduler_thread.join(timeout=5)
    
    def _simple_scheduler_worker(self):
        """简单调度器工作线程"""
        self.logger.info("简单调度器工作线程已启动")
        
        while self.simple_scheduler_running:
            try:
                current_time = datetime.now()
                
                with self.lock:
                    tasks_to_run = []
                    
                    for task in self.tasks.values():
                        if not task.enabled or task.status == TaskStatus.RUNNING:
                            continue
                        
                        should_run = False
                        
                        if task.task_type == TaskType.INTERVAL:
                            if task.last_run_time is None:
                                should_run = True
                            else:
                                time_diff = (current_time - task.last_run_time).total_seconds()
                                if time_diff >= task.interval_seconds:
                                    should_run = True
                        
                        elif task.task_type == TaskType.ONCE:
                            if task.run_date and current_time >= task.run_date and task.status != TaskStatus.COMPLETED:
                                should_run = True
                        
                        elif task.task_type == TaskType.CRON:
                            # 简化的cron处理，只支持基本格式
                            if self._should_run_cron_task(task, current_time):
                                should_run = True
                        
                        if should_run:
                            tasks_to_run.append(task.id)
                
                # 执行需要运行的任务
                for task_id in tasks_to_run:
                    threading.Thread(
                        target=self._execute_task,
                        args=(task_id,),
                        name=f"Task-{task_id}"
                    ).start()
                
                time.sleep(1)  # 每秒检查一次
                
            except Exception as e:
                self.logger.error(f"简单调度器异常: {e}")
                time.sleep(5)
        
        self.logger.info("简单调度器工作线程已停止")
    
    def _should_run_cron_task(self, task: ScheduledTask, current_time: datetime) -> bool:
        """检查cron任务是否应该运行（简化实现）"""
        if not task.cron_expression:
            return False
        
        # 如果上次运行时间在同一分钟内，不重复运行
        if task.last_run_time:
            if (current_time.year == task.last_run_time.year and
                current_time.month == task.last_run_time.month and
                current_time.day == task.last_run_time.day and
                current_time.hour == task.last_run_time.hour and
                current_time.minute == task.last_run_time.minute):
                return False
        
        # 简化的cron表达式解析，只支持基本格式
        # 格式：分钟 小时 日 月 星期
        try:
            parts = task.cron_expression.split()
            if len(parts) < 5:
                return False
            
            minute_expr, hour_expr, day_expr, month_expr, weekday_expr = parts[:5]
            
            # 检查分钟
            if minute_expr != '*' and str(current_time.minute) != minute_expr:
                return False
            
            # 检查小时
            if hour_expr != '*' and str(current_time.hour) != hour_expr:
                return False
            
            # 检查日期
            if day_expr != '*' and str(current_time.day) != day_expr:
                return False
            
            # 检查月份
            if month_expr != '*' and str(current_time.month) != month_expr:
                return False
            
            # 检查星期（0=星期日，1=星期一...6=星期六）
            if weekday_expr != '*':
                weekday = current_time.weekday()  # Python中0=星期一
                cron_weekday = (weekday + 1) % 7  # 转换为cron格式
                if str(cron_weekday) != weekday_expr:
                    return False
            
            return True
            
        except Exception:
            return False
    
    # 预定义的常用任务
    def add_system_cleanup_task(self):
        """添加系统清理任务"""
        def cleanup():
            self.logger.info("执行系统清理任务")
            # 这里可以添加具体的清理逻辑
        
        self.add_cron_task(
            task_id="system_cleanup",
            name="系统清理",
            func=cleanup,
            cron_expression="0 2 * * *"  # 每天凌晨2点
        )
    
    def add_health_check_task(self, check_func: Callable):
        """添加健康检查任务"""
        self.add_interval_task(
            task_id="health_check",
            name="健康检查",
            func=check_func,
            interval_seconds=60  # 每分钟检查一次
        )
    
    def add_data_archive_task(self, archive_func: Callable):
        """添加数据归档任务"""
        self.add_cron_task(
            task_id="data_archive",
            name="数据归档",
            func=archive_func,
            cron_expression="0 1 * * *"  # 每天凌晨1点
        ) 